﻿/*
 * 创建人：金鑫
 * 创建时间：2022/8/26
 * 
 * *******************************************************************
 * 
 * 功能描述：定时任务服务实现
 * 
 * *******************************************************************
 * 修改履历：
 * 
 * *******************************************************************
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using XfTechOAWeb.IService;
using XfTechOAWeb.Models;
using XfTechOAWeb.Dtos.Timing;
using XfTechOAWeb.Data;
using Quartz;
using Quartz.Impl;
using XfTechOAWeb.Service.Tasks;
using XfTechOAWeb.Data.Base;

namespace XfTechOAWeb.Service
{
    /// <summary>
    /// 定时任务服务实现
    /// </summary>
    public class TimingService : ITimingService
    {
        IRepository<Timing> repository;
        ITimingRepository timingRepository;
        IScheduler scheduler;
        ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
      

        public TimingService(IRepository<Timing> repository, ITimingRepository timingRepository)
        {
            this.timingRepository = timingRepository;
            this.repository = repository;
           
        }

        #region   数据库部分
        /// <summary>
        /// 获取全部Job任务信息
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public PageDto GetTimingList(TimingPage data)
        {
            List<Timing> TimingList = repository.Table.ToList();
            int count = TimingList.Count();
            TimingList = TimingList.Skip(data.Pindex * data.Psize - data.Psize).Take(data.Psize).ToList();
            return new PageDto { data = TimingList, count = count };
        }

        /// <summary>
        /// 删除Job任务信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public BaseResult DeleteTiming(int id)
        {
            var s = timingRepository.Remove(id);
            if (s)
            {
                return new BaseResult { Data = s, Msg = "成功", Code = 200 };
            }
            else
            {
                return new BaseResult { Data = s, Msg = "失败", Code = 500 };
            }

        }

        /// <summary>
        /// 添加Job信息
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public BaseResult AddTiming(Timing data)
        {
            repository.Insert(data);
            bool d = repository.SaveChanges() > 0;
            if (d)
            {
                return new BaseResult { Data = d, Msg = "成功", Code = 200 };
            }
            else
            {
                return new BaseResult { Data = d, Msg = "失败", Code = 500 };
            }
        }

        /// <summary>
        /// 修改单个Job状态
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public bool UptZt(int Id,int i)
        {
            return timingRepository.UptZt(Id,i);
        }

        /// <summary>
        /// 纠正状态
        /// </summary>
        /// <returns></returns>
        BaseResult ITimingService.CorrectJob()
        {
            List<Timing> TimingData = repository.Table.ToList();
            TimingData = TimingData.Where(x => x.Zt != 0).ToList();
            foreach (var a in TimingData)
            {
                a.Zt = 0;
            }
            return new BaseResult {Data=repository.SaveChanges() > 0 ,Msg="重构完毕",Code=200 };
        }

        #endregion

        #region  调度器部分
        /// <summary>
        /// 启动Job任务
        /// </summary>
        /// <param name="data">Job信息</param>
        /// <returns></returns>
        public async Task<BaseResult> StartScheduleJob(TimingDto data)
        {
            JobKey Job = GetJobkeys(data.JobGroup, data.JobName);//JobKey
            scheduler = OnePackageService();
            if (await scheduler.CheckExists(Job))
            {
                return (new BaseResult
                {
                    Msg = "已有重复Job任务",
                    Code = 500,
                    Data = null
                });//该Job正在运行，直接结束
            }

            //若运行Job中不存在该Job,就接着敲JobDetail和Trigger（时间策略）

            #region   JobDetail
            var types = AppDomain.CurrentDomain.GetAssemblies()
             .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IJob)))).ToList();
            Type tss = types.Where(x => x.FullName == data.RequestUrl).FirstOrDefault(); //用反射获取了第一个相同命名路径的对象（因为结果会是一个集合）

            IJobDetail jobDetail = JobBuilder.Create(tss) //刚才通过反射拿到的给它用上
              .WithIdentity(data.JobName, data.JobGroup)//Job名称，分组名(后面都通过这个来查找)
              .WithDescription(data.Description)//描述
              .Build();
             jobDetail.JobDataMap.Add("JobId", data.Id);//给拦截器用的主键Id
            #endregion

            #region   Trigger
            ITrigger trigger;
            if (data.TriggerType == "Cron")
            {
                trigger = CreateCrontrigger(data);//创建使用Cron来进行的Trigger
            }
            else
            {
                trigger = CreateSimpletrigger(data);//创建使用Simple来进行的Trigger
            }
            #endregion

            await scheduler.ScheduleJob(jobDetail, trigger);//加入
            await scheduler.Start();

            var i = 1;
          
            if (UptZt(data.Id,i))
            {
                return new BaseResult
                {
                    Msg = "成功",
                    Code = 200,
                    Data = null
                };
            }
            else
            {
                return new BaseResult
                {
                    Msg = "失败",
                    Code = 500,
                    Data = null
                };
            }

        }

        /// <summary>
        ///暂停Job任务
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<BaseResult> PauseScheduleJob(DeleteJobDto data)
        {
            JobKey Job = GetJobkeys(data.JobGroup, data.JobName);
            try
            {
                scheduler = OnePackageService();
                if (await scheduler.CheckExists(Job))
                {
                    await scheduler.PauseJob(Job);// PauseJob暂停任务   
                    var i = 2;
                    if (UptZt(data.JobId, i))
                    {
                        return (new BaseResult { Code = 200, Msg = "请求成功！已处理！" });
                    }
                    else
                    {
                        return new BaseResult
                        {
                            Msg = "失败",
                            Code = 500,
                            Data = null
                        };
                    }
                }
                else
                {
                    return (new BaseResult { Code = 500, Msg = "当前任务不存在或已结束" });
                }
            }
            catch (Exception)
            {
                return (new BaseResult
                {
                    Msg = "请求错误",
                    Code = 500,
                    Data = null
                });
                throw;
            }
        }

        /// <summary>
        /// 恢复Job任务
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public async Task<BaseResult> RecoverScheduleJob(StartJobDto data)
        {
            JobKey Job = GetJobkeys(data.JobGroup, data.JobName);
            try
            {
                scheduler = OnePackageService();
                // IScheduler scheduler = await schedulerFactory.GetScheduler();
                if (await scheduler.CheckExists(Job))
                {
                    await scheduler.ResumeJob(Job);//恢复Job任务
                    var i = 1;
                    
                    if (UptZt(data.JobId, i))
                    {
                        return new BaseResult
                        {
                            Msg = "成功",
                            Code = 200,
                            Data = null
                        };
                    }
                    else
                    {
                        return new BaseResult
                        {
                            Msg = "失败",
                            Code = 500,
                            Data = null
                        };
                    }
                }
                else
                {
                    return (new BaseResult { Code = 500, Msg = "不存在该任务" });
                }
            }
            catch (Exception)
            {
                return (new BaseResult { Code = 500, Msg = "错误" });
                throw;
            }
        }

        #region`调度器快捷夹
        /// <summary>
        /// 生成JobKey（需要分区名称和Job名称）
        /// </summary>
        /// <param name="GroupName"></param>
        /// <param name="JObName"></param>
        /// <returns></returns>
        public JobKey GetJobkeys(string GroupName, string JObName)
        {
            JobKey Job = new JobKey(JObName, GroupName);
            return Job;
        }

        /// <summary>
        /// 创建Cron_Trigger
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public ITrigger CreateCrontrigger(TimingDto data)
        {
            //if (DateTime.Now > data.EndTime)
            //{
            //    data.BeginTime = DateTime.Now;
            //}
            ITrigger triggered = TriggerBuilder.Create()
                 .WithIdentity(data.JobName, data.JobGroup)
                 // .StartAt(data.BeginTime)//从指定时间开始执行
                 //.EndAt(data.EndTime)//指定时间结束
                 .WithCronSchedule(data.Cron)
                 .Build();
            return triggered;
        }

        /// <summary>
        /// 创建Simple_Trigger
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        public ITrigger CreateSimpletrigger(TimingDto data)
        {
            ITrigger trigger = TriggerBuilder.Create()
                  .WithIdentity(data.JobName, data.JobGroup)
                    // .StartNow()//启动时立马执行一次，不占用执行次数
                    // .StartAt(data.BeginTime)//从指定时间开始执行
                    .WithSimpleSchedule(w =>
                    {
                        if (data.Yun)
                        {
                            w.WithIntervalInSeconds((int)data.IntervalSecond).RepeatForever();//一直按照Simple间执行
                            //x秒执行一次/一直启用
                        }
                        else
                        {
                            w.WithIntervalInSeconds((int)data.IntervalSecond).WithRepeatCount((int)data.RumTimes);//到了Simple次数后自动结束
                                                                                                                  //x秒执行一次/一共只会执行x次
                        }
                    })
                 .Build();
            return trigger;
        }

        /// <summary>
        /// 一条龙服务（对scheduler的配置）
        /// </summary>
        /// <returns></returns>
        public   IScheduler   OnePackageService() 
        {
            scheduler= schedulerFactory.GetScheduler().Result;
         //   scheduler.ListenerManager.AddJobListener(new JobMonitor(timingRepository));//Job监听器
        //   scheduler.ListenerManager.AddTriggerListener();//Trigger监听器
            scheduler.ListenerManager.AddSchedulerListener(new  SchedulerMonitor(timingRepository));//SchedulerJob监听器

            return scheduler;
        }

        #endregion

        #endregion




        #region  反射
        /// <summary>
        /// 反射拿取全部继承了IJob接口的命名路由
        /// </summary>
        /// <returns></returns>
        List<dynamic> ITimingService.After()
        {
            List<dynamic> data = new List<dynamic>();
            var types = AppDomain.CurrentDomain.GetAssemblies()
                .SelectMany(a => a.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IJob)))).ToList();
            types.ForEach(x =>
            {
                data.Add(new
                {
                    Namespace = x.FullName,
                    Name = x.Name,
                    value = x.FullName,
                });
            });
            return data;
        }
        #endregion




    }
}
